#IT326 Project

Description of the dataset:

This dataset, obtained from vgchartz.com, provides a valuable resource for exploring the dynamics between gaming platforms and genres in the top 100 global video games. It enables us to analyze the platforms that are influencing worldwide sales, identify the most prosperous genres in various global regions, and track the evolving trends in both platform preference and genre popularity over time.

Our goal:

Our goal from studying this dataset is to utilize classification and clustering techniques on the input data to make predictions about the popularity of upcoming games.

Attributes description:

Attributes name Description Data type
Rank Ranking of the game based on global sales. Numeric
Name Name of the game. Nominal
Platform Platform the game was released on. Nominal
Year Year the game was released. Ordinal
Genre Genre of the game Nominal
Publisher Publisher of the game. Nominal
NA_Sales Sales of the game in North America Numeric (ratio-scaled)
EU_Sales Sales of the game in Europe Numeric (ratio-scaled)
JP_Sales Sales of the game in Japan Numeric (ratio-scaled)
Other_Sales Sales of the game in other regions Numeric (ratio-scaled)
Global_Sales Total sales of the game worldwide Numeric (ratio-scaled)

Class label:

Popular’ is our class label, we will use Global_Sales attribute to predict whether a game will sell 1000000 or more globally. Our task of data mining is regression.

Importing our dataset:

dataset=read.csv("vgsales.csv")

loading libraries needed for our data mining tasks:

library(outliers) 
library(dplyr)
library(Hmisc)
library(ggplot2)
library(cowplot)
library(mlbench)
library(caret)
library(faux)
library(DataExplorer)
library(randomForest)
options(max.print=9999999)

General info about our dataset including number of rows and columns, and cheking dimensionality and coulumns names:

nrow(dataset)
ncol(dataset)
dim(dataset)
names(dataset)
<<<<<<< HEAD
[1] 16598
ncol(dataset)
[1] 11
dim(dataset)
[1] 16598    11
names(dataset)
 [1] "Rank"         "Name"         "Platform"     "Year"         "Genre"        "Publisher"    "NA_Sales"     "EU_Sales"     "JP_Sales"     "Other_Sales" 
[11] "Global_Sales"
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

Dataset structure including number of coulums and rows, attribute types:

str(dataset)

sample of raw dataset(first 10 rows):

head(dataset, 10)
<<<<<<< HEAD
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

sample of raw dataset(last 10 rows):

tail(dataset, 10)
<<<<<<< HEAD
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

summary of our dataset:

summary(dataset)
<<<<<<< HEAD
      Rank           Name             Platform             Year              Genre            Publisher            NA_Sales          EU_Sales      
 Min.   :    1   Length:16598       Length:16598       Length:16598       Length:16598       Length:16598       Min.   : 0.0000   Min.   : 0.0000  
 1st Qu.: 4151   Class :character   Class :character   Class :character   Class :character   Class :character   1st Qu.: 0.0000   1st Qu.: 0.0000  
 Median : 8300   Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character   Median : 0.0800   Median : 0.0200  
 Mean   : 8301                                                                                                  Mean   : 0.2647   Mean   : 0.1467  
 3rd Qu.:12450                                                                                                  3rd Qu.: 0.2400   3rd Qu.: 0.1100  
 Max.   :16600                                                                                                  Max.   :41.4900   Max.   :29.0200  
    JP_Sales         Other_Sales        Global_Sales    
 Min.   : 0.00000   Min.   : 0.00000   Min.   : 0.0100  
 1st Qu.: 0.00000   1st Qu.: 0.00000   1st Qu.: 0.0600  
 Median : 0.00000   Median : 0.01000   Median : 0.1700  
 Mean   : 0.07778   Mean   : 0.04806   Mean   : 0.5374  
 3rd Qu.: 0.04000   3rd Qu.: 0.04000   3rd Qu.: 0.4700  
 Max.   :10.22000   Max.   :10.57000   Max.   :82.7400  
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

variance of numeric data:

var(dataset$NA_Sales)
var(dataset$EU_Sales)
var(dataset$JP_Sales)
var(dataset$Other_Sales)
var(dataset$Global_Sales)

Graphs:

dataset2 <- dataset %>% sample_n(50)
tab <- dataset2$Platform %>% table()
precentages <- tab %>% prop.table() %>% round(3) * 100 
txt <- paste0(names(tab), '\n', precentages, '%') 

pie(tab, labels=txt , main = "Pie chart of Platform") 
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

We notice from the pie chart of platform attribute that releasing a game for PS users will increase the popularity of the game since it is the most common platform among gamers.

# coloring barplot and adding text
tab<-dataset$Genre %>% table() 

precentages<-tab %>% prop.table() %>% round(3)*100 

txt<-paste0(names(tab), '\n',precentages,'%') 

bb <- dataset$Genre %>% table() %>% barplot(axisnames=F, main = "Barplot for Popular genres ",ylab='count',col=c('pink','blue','lightblue','green','lightgreen','red','orange','red','grey','yellow','azure','olivedrab')) 

text(bb,tab/2,labels=txt,cex=1.5) 
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

In terms of genre, action games are the most popular, followed by sports and music games. It is safe to assume that a high number of genres of this nature exist due to their popularity and sales.

boxplot(dataset$NA_Sales , main="
BoxPlot for NA_Sales")
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
boxplot(dataset$EU_Sales, main="
 BoxPlot for EU_Sales")
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
boxplot(dataset$JP_Sales , main="
 BoxPlot for JP_Sales")
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
boxplot(dataset$Other_Sales , main="
 BoxPlot for Other_Sales") 
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

The boxplot of the Other-sales attribute indicate that the values are close to each other ,and there is a lot of outliers since the dataset represents the global sales of video games.

boxplot(dataset$Global_Sales , main="BoxPlot for Global_Sales")
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

The boxplot of the Global-sales attribute indicate that the values are close to each other ,and there is a lot of outliers since the dataset represents the global sales of video games.

qplot(data = dataset, x=Global_Sales,y=Genre,fill=I("yellow"),width=0.5 ,geom = "boxplot" , main = "BoxPlots for genre and Global_Sales")
<<<<<<< HEAD
Warning: `qplot()` was deprecated in ggplot2 3.4.0.

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
dataset$Year %>% table() %>% barplot( main = "Barplot for year")
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
pairs(~NA_Sales + EU_Sales + JP_Sales + Other_Sales + Global_Sales, data = dataset,
      main = "Sales Scatterplot")
<<<<<<< HEAD

======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

We used Scatterplot to determine the type of correlation we have between the sales; we can see that the majority have positive correlation with each other.

Pre - processing

Varaible transformation

dataset$Rank=as.character(dataset$Rank)

We transformed the Rank from numric to char,because we will use them as ordinal data.

Null checking

sum(is.na(dataset$Rank))
NullRank<-dataset[dataset$Rank=="N/A",]
NullRank
<<<<<<< HEAD
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

checking for nulls in Rank (there is no nulls)

sum(is.na(dataset$Name))
[1] 0
NullName<-dataset[dataset$Name=="N/A",]
NullName

checking for nulls in name (there is no nulls)

sum(is.na(dataset$Platform))
NullPlatform<-dataset[dataset$Platform=="N/A",]

checking for nulls in Platform(there is no nulls)

<<<<<<< HEAD
sum(is.na(dataset$Year))
[1] 0
NullYear<-dataset[dataset$Year=="N/A",]
NullYear
=======
sum(is.na(dataset$Year))
NullYear<-dataset[dataset$Year=="N/A",]
NullYear
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

checking for nulls in year we won’t delete the null and we will leave them as global constant because we want the sales data out of them.

sum(is.na(dataset$Genre))
NullGenre<-dataset[dataset$Genre=="N/A",]
NullGenre
<<<<<<< HEAD
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

checking for nulls in Genre(there is no nulls)

sum(is.na(dataset$Publisher))
NullPublisher<-dataset[dataset$Publisher=="N/A",]
NullPublisher
<<<<<<< HEAD
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

checking for nulls in Publisher. we won’t delete the null and we will leave them as global constant as it is because we want the sales data of them.

sum(is.na(dataset$Other_Sales))
NullOther_Sales<-dataset[dataset$Other_Sales=="N/A",]

There is no null values in the other_sales.

sum(is.na(dataset$Global_Sales))
NullGlobal_Sales<-dataset[dataset$Global_Saless=="N/A",]

There is no null values in the Global_Sales.

Encoding

dataset$Platform=factor(dataset$Platform,levels=c("2600","3DO","3DS","DC","DS","GB","GBA","GC","GEN","GG","N64","NES","NG","PC","PCFX","PS","PS2","PS3","PS4","PSP","PSV","SAT","SCD","SNES","TG16","Wii","WiiU","WS","X360","XB","XOne"), labels=c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31))

Since most machine learning algorithms work with numbers and not with text or categorical variables, this column will be encoded to facilitate our data mining task.

dataset$Genre=factor(dataset$Genre,levels=c("Action","Adventure","Fighting","Platform","Puzzle","Racing","Role-Playing","Shooter","Simulation","Sports","Strategy","Misc"),labels=c(1,2,3,4,5,6,7,8,9,10,11,12))

Since most machine learning algorithms work with numbers and not with text or categorical variables, this column will be encoded to facilitate our data mining task.

Outliers

outlier of NA_Sales

OutNA_Sales = outlier(dataset$NA_Sales, logical =TRUE)
sum(OutNA_Sales)
Find_outlier = which(OutNA_Sales ==TRUE, arr.ind = TRUE)
OutNA_Sales
Find_outlier

outlier of EU_Sales

OutEU_Sales = outlier(dataset$EU_Sales, logical =TRUE)
sum(OutEU_Sales)
Find_outlier = which(OutEU_Sales ==TRUE, arr.ind = TRUE)
OutEU_Sales
Find_outlier

outlier of JP_Sales

OutJP_Sales = outlier(dataset$JP_Sales, logical =TRUE)
sum(OutJP_Sales)
Find_outlier = which(OutJP_Sales ==TRUE, arr.ind = TRUE)
OutJP_Sales
Find_outlier

outlier of other_sales

OutOS=outlier(dataset$Other_Sales, logical=TRUE)  
sum(OutOS)  
Find_outlier=which(OutOS==TRUE, arr.ind=TRUE)  
OutOS 
Find_outlier 

outlier of Global_sales

OutGS=outlier(dataset$Global_Sales, logical=TRUE)  
sum(OutGS)  
Find_outlier=which(OutGS==TRUE, arr.ind=TRUE)  
OutGS 
Find_outlier 

Remove outliers

dataset= dataset[-Find_outlier,]

Normalization

Dataset before normalization:

datsetWithoutNormalization<-dataset
normalize <- function(x) {return ((x - min(x)) / (max(x) - min(x)))}
dataset$NA_Sales<-normalize(datsetWithoutNormalization$NA_Sales)
dataset$EU_Sales<-normalize(datsetWithoutNormalization$EU_Sales)
dataset$JP_Sales<-normalize(datsetWithoutNormalization$JP_Sales)
dataset$Other_Sales<-normalize(datsetWithoutNormalization$Other_Sales)
dataset$Global_Sales<-normalize(datsetWithoutNormalization$Global_Sales)

We chose min-max normalization instead of z-score normalization because min-max transform the data into a specific range, which enhances its suitability for visualization and comparison. Additionally, it simplifies the process of assessing attribute importance and their contributions to the model.

Feautre selection

Our class label (popular) refers to Global_Sales. Other sales regions will be evaluated based on their importance to (global_sales) column. and those that are less important will be deleted from the dataset. use roc_curve area as score

roc_imp <- filterVarImp(x = dataset[,7:10], y = dataset$Global_Sales)

sort the score in decreasing order

roc_imp <- data.frame(cbind(variable = rownames(roc_imp), score = roc_imp[,1]))
roc_imp$score <- as.double(roc_imp$score)
roc_imp[order(roc_imp$score,decreasing = TRUE),]
<<<<<<< HEAD
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f

we will remove the (JP_Sales) because it is of low importance to our class_label(Global_Sales)

dataset<- dataset[,-9]

Dataset after pre-processing

print(dataset)
<<<<<<< HEAD
======= >>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
<<<<<<< HEAD
LS0tCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KI0lUMzI2IFByb2plY3QKCgoKCiMgRGVzY3JpcHRpb24gb2YgdGhlIGRhdGFzZXQ6CgpUaGlzIGRhdGFzZXQsIG9idGFpbmVkIGZyb20gdmdjaGFydHouY29tLCBwcm92aWRlcyBhIHZhbHVhYmxlIHJlc291cmNlIGZvciBleHBsb3JpbmcgdGhlIGR5bmFtaWNzIGJldHdlZW4gZ2FtaW5nIHBsYXRmb3JtcyBhbmQgZ2VucmVzIGluIHRoZSB0b3AgMTAwIGdsb2JhbCB2aWRlbyBnYW1lcy4gSXQgZW5hYmxlcyB1cyB0byBhbmFseXplIHRoZSBwbGF0Zm9ybXMgdGhhdCBhcmUgaW5mbHVlbmNpbmcgd29ybGR3aWRlIHNhbGVzLCBpZGVudGlmeSB0aGUgbW9zdCBwcm9zcGVyb3VzIGdlbnJlcyBpbiB2YXJpb3VzIGdsb2JhbCByZWdpb25zLCBhbmQgdHJhY2sgdGhlIGV2b2x2aW5nIHRyZW5kcyBpbiBib3RoIHBsYXRmb3JtIHByZWZlcmVuY2UgYW5kIGdlbnJlIHBvcHVsYXJpdHkgb3ZlciB0aW1lLiAKCiMgU291cmNlIGFuZCBsaW5rOgpTb3VyY2U6IEthZ2dsZQoKVVJMIGxpbms6IGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZ3JlZ29ydXQvdmlkZW9nYW1lc2FsZXMKCiMgT3VyIGdvYWw6CgpPdXIgZ29hbCAgZnJvbSBzdHVkeWluZyB0aGlzIGRhdGFzZXQgaXMgdG8gdXRpbGl6ZSBjbGFzc2lmaWNhdGlvbiBhbmQgY2x1c3RlcmluZyB0ZWNobmlxdWVzIG9uIHRoZSBpbnB1dCBkYXRhIHRvIG1ha2UgcHJlZGljdGlvbnMgYWJvdXQgdGhlIHBvcHVsYXJpdHkgb2YgdXBjb21pbmcgZ2FtZXMuCgoKCiMgQXR0cmlidXRlcyBkZXNjcmlwdGlvbjoKCgp8ICoqQXR0cmlidXRlcyBuYW1lKiogfCAqKkRlc2NyaXB0aW9uKiogICAgICAgICAgICAgICAgICAgfCAqKkRhdGEgdHlwZSoqIHwgCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfFJhbmsgICAgICAgICAgICAgICB8IFJhbmtpbmcgb2YgdGhlIGdhbWUgYmFzZWQgb24gZ2xvYmFsIHNhbGVzLiB8IE51bWVyaWMgICAgICAgfAp8IE5hbWUgICAgICAgICAgICB8IE5hbWUgb2YgdGhlIGdhbWUuIHwgTm9taW5hbCAgICAgICB8IAp8IFBsYXRmb3JtICAgICAgfCBQbGF0Zm9ybSB0aGUgZ2FtZSB3YXMgcmVsZWFzZWQgb24uIHwgTm9taW5hbCAgICAgICB8IAp8IFllYXIgICAgICAgICAgICAgICB8IFllYXIgdGhlIGdhbWUgd2FzIHJlbGVhc2VkLiB8IE9yZGluYWwgICAgICAgfCAKfCBHZW5yZSAgICAgICAgICAgIHwgR2VucmUgb2YgdGhlIGdhbWUgfCBOb21pbmFsICAgICAgIHwgCnwgUHVibGlzaGVyICAgICAgfCBQdWJsaXNoZXIgb2YgdGhlIGdhbWUuIHwgTm9taW5hbCAgICAgICB8IAp8IE5BX1NhbGVzICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBOb3J0aCBBbWVyaWNhIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgICB8IAp8IEVVX1NhbGVzICAgICAgIHwgU2FsZXMgb2YgdGhlIGdhbWUgaW4gRXVyb3BlIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgICAgfCAKfCBKUF9TYWxlcyAgICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBKYXBhbiB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgIHwgCnwgT3RoZXJfU2FsZXMgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBvdGhlciByZWdpb25zIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgICAgfCAKfCBHbG9iYWxfU2FsZXMgIHwgVG90YWwgc2FsZXMgb2YgdGhlIGdhbWUgd29ybGR3aWRlIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgfCAgICAgCgoKIyBDbGFzcyBsYWJlbDoKClBvcHVsYXInIGlzIG91ciBjbGFzcyBsYWJlbCwgd2Ugd2lsbCB1c2UgR2xvYmFsX1NhbGVzIGF0dHJpYnV0ZSB0byBwcmVkaWN0IHdoZXRoZXIgYSBnYW1lIHdpbGwgc2VsbCAxMDAwMDAwIG9yIG1vcmUgZ2xvYmFsbHkuIE91ciB0YXNrIG9mIGRhdGEgbWluaW5nIGlzIHJlZ3Jlc3Npb24uCgoKCgoKCgoKCkltcG9ydGluZyBvdXIgZGF0YXNldDoKYGBge3J9CmRhdGFzZXQ9cmVhZC5jc3YoInZnc2FsZXMuY3N2IikKYGBgCgoKbG9hZGluZyBsaWJyYXJpZXMgbmVlZGVkIGZvciBvdXIgZGF0YSBtaW5pbmcgdGFza3M6CmBgYHtyfQpsaWJyYXJ5KG91dGxpZXJzKSAKbGlicmFyeShkcGx5cikKbGlicmFyeShIbWlzYykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWxiZW5jaCkKbGlicmFyeShjYXJldCkKbGlicmFyeShmYXV4KQpsaWJyYXJ5KERhdGFFeHBsb3JlcikKbGlicmFyeShyYW5kb21Gb3Jlc3QpCm9wdGlvbnMobWF4LnByaW50PTk5OTk5OTkpCmBgYAoKCgoKR2VuZXJhbCBpbmZvIGFib3V0IG91ciBkYXRhc2V0IGluY2x1ZGluZyAgbnVtYmVyIG9mIHJvd3MgYW5kIGNvbHVtbnMsIGFuZCBjaGVraW5nIGRpbWVuc2lvbmFsaXR5IGFuZCBjb3VsdW1ucyBuYW1lczoKYGBge3J9Cm5yb3coZGF0YXNldCkKbmNvbChkYXRhc2V0KQpkaW0oZGF0YXNldCkKbmFtZXMoZGF0YXNldCkKYGBgCgoKCgpEYXRhc2V0IHN0cnVjdHVyZSBpbmNsdWRpbmcgbnVtYmVyIG9mIGNvdWx1bXMgYW5kIHJvd3MsIGF0dHJpYnV0ZSB0eXBlczoKYGBge3J9CnN0cihkYXRhc2V0KQpgYGAKCgoKc2FtcGxlIG9mIHJhdyBkYXRhc2V0KGZpcnN0IDEwIHJvd3MpOgpgYGB7cn0KaGVhZChkYXRhc2V0LCAxMCkKYGBgCgpzYW1wbGUgb2YgcmF3IGRhdGFzZXQobGFzdCAxMCByb3dzKToKYGBge3J9CnRhaWwoZGF0YXNldCwgMTApCmBgYAoKc3VtbWFyeSBvZiBvdXIgZGF0YXNldDoKYGBge3J9CnN1bW1hcnkoZGF0YXNldCkKYGBgCgp2YXJpYW5jZSBvZiBudW1lcmljIGRhdGE6CmBgYHtyfQp2YXIoZGF0YXNldCROQV9TYWxlcykKdmFyKGRhdGFzZXQkRVVfU2FsZXMpCnZhcihkYXRhc2V0JEpQX1NhbGVzKQp2YXIoZGF0YXNldCRPdGhlcl9TYWxlcykKdmFyKGRhdGFzZXQkR2xvYmFsX1NhbGVzKQpgYGAKCgoKCgoKIyBHcmFwaHM6CgpgYGB7cn0KZGF0YXNldDIgPC0gZGF0YXNldCAlPiUgc2FtcGxlX24oNTApCnRhYiA8LSBkYXRhc2V0MiRQbGF0Zm9ybSAlPiUgdGFibGUoKQpwcmVjZW50YWdlcyA8LSB0YWIgJT4lIHByb3AudGFibGUoKSAlPiUgcm91bmQoMykgKiAxMDAgCnR4dCA8LSBwYXN0ZTAobmFtZXModGFiKSwgJ1xuJywgcHJlY2VudGFnZXMsICclJykgCgpwaWUodGFiLCBsYWJlbHM9dHh0ICwgbWFpbiA9ICJQaWUgY2hhcnQgb2YgUGxhdGZvcm0iKSAKCmBgYAoKV2Ugbm90aWNlIGZyb20gdGhlIHBpZSBjaGFydCBvZiBwbGF0Zm9ybSBhdHRyaWJ1dGUgdGhhdCByZWxlYXNpbmcgYSBnYW1lIGZvciBQUyB1c2VycyB3aWxsIGluY3JlYXNlIHRoZSBwb3B1bGFyaXR5IG9mIHRoZSBnYW1lIHNpbmNlIGl0IGlzIHRoZSBtb3N0IGNvbW1vbiBwbGF0Zm9ybSBhbW9uZyBnYW1lcnMuIAoKCgoKCmBgYHtyfQojIGNvbG9yaW5nIGJhcnBsb3QgYW5kIGFkZGluZyB0ZXh0CnRhYjwtZGF0YXNldCRHZW5yZSAlPiUgdGFibGUoKSAKCnByZWNlbnRhZ2VzPC10YWIgJT4lIHByb3AudGFibGUoKSAlPiUgcm91bmQoMykqMTAwIAoKdHh0PC1wYXN0ZTAobmFtZXModGFiKSwgJ1xuJyxwcmVjZW50YWdlcywnJScpIAoKYmIgPC0gZGF0YXNldCRHZW5yZSAlPiUgdGFibGUoKSAlPiUgYmFycGxvdChheGlzbmFtZXM9RiwgbWFpbiA9ICJCYXJwbG90IGZvciBQb3B1bGFyIGdlbnJlcyAiLHlsYWI9J2NvdW50Jyxjb2w9YygncGluaycsJ2JsdWUnLCdsaWdodGJsdWUnLCdncmVlbicsJ2xpZ2h0Z3JlZW4nLCdyZWQnLCdvcmFuZ2UnLCdyZWQnLCdncmV5JywneWVsbG93JywnYXp1cmUnLCdvbGl2ZWRyYWInKSkgCgp0ZXh0KGJiLHRhYi8yLGxhYmVscz10eHQsY2V4PTEuNSkgCmBgYApJbiB0ZXJtcyBvZiBnZW5yZSwgYWN0aW9uIGdhbWVzIGFyZSB0aGUgbW9zdCBwb3B1bGFyLCBmb2xsb3dlZCBieSBzcG9ydHMgYW5kIG11c2ljIGdhbWVzLiBJdCBpcyBzYWZlIHRvIGFzc3VtZSB0aGF0IGEgaGlnaCBudW1iZXIgb2YgZ2VucmVzIG9mIHRoaXMgbmF0dXJlIGV4aXN0IGR1ZSB0byB0aGVpciBwb3B1bGFyaXR5IGFuZCBzYWxlcy4KCgoKCgpgYGB7cn0KYm94cGxvdChkYXRhc2V0JE5BX1NhbGVzICwgbWFpbj0iCkJveFBsb3QgZm9yIE5BX1NhbGVzIikKYGBgCgpgYGB7cn0KYm94cGxvdChkYXRhc2V0JEVVX1NhbGVzLCBtYWluPSIKIEJveFBsb3QgZm9yIEVVX1NhbGVzIikKYGBgCgpgYGB7cn0KYm94cGxvdChkYXRhc2V0JEpQX1NhbGVzICwgbWFpbj0iCiBCb3hQbG90IGZvciBKUF9TYWxlcyIpCmBgYAoKCgoKYGBge3J9CmJveHBsb3QoZGF0YXNldCRPdGhlcl9TYWxlcyAsIG1haW49IgogQm94UGxvdCBmb3IgT3RoZXJfU2FsZXMiKSAKYGBgICAKClRoZSBib3hwbG90IG9mIHRoZSBPdGhlci1zYWxlcyBhdHRyaWJ1dGUgaW5kaWNhdGUgdGhhdCB0aGUgdmFsdWVzIGFyZSBjbG9zZSB0byBlYWNoIG90aGVyICxhbmQgdGhlcmUgaXMgYSBsb3Qgb2Ygb3V0bGllcnMgc2luY2UgdGhlIGRhdGFzZXQgcmVwcmVzZW50cyB0aGUgZ2xvYmFsIHNhbGVzIG9mIHZpZGVvIGdhbWVzLiAKCgoKCmBgYHtyfQpib3hwbG90KGRhdGFzZXQkR2xvYmFsX1NhbGVzICwgbWFpbj0iQm94UGxvdCBmb3IgR2xvYmFsX1NhbGVzIikKCmBgYCAgClRoZSBib3hwbG90IG9mIHRoZSBHbG9iYWwtc2FsZXMgYXR0cmlidXRlIGluZGljYXRlIHRoYXQgdGhlIHZhbHVlcyBhcmUgY2xvc2UgdG8gZWFjaCBvdGhlciAsYW5kIHRoZXJlIGlzIGEgbG90IG9mIG91dGxpZXJzIHNpbmNlIHRoZSBkYXRhc2V0IHJlcHJlc2VudHMgdGhlIGdsb2JhbCBzYWxlcyBvZiB2aWRlbyBnYW1lcy4gCgoKCgpgYGB7cn0KcXBsb3QoZGF0YSA9IGRhdGFzZXQsIHg9R2xvYmFsX1NhbGVzLHk9R2VucmUsZmlsbD1JKCJ5ZWxsb3ciKSx3aWR0aD0wLjUgLGdlb20gPSAiYm94cGxvdCIgLCBtYWluID0gIkJveFBsb3RzIGZvciBnZW5yZSBhbmQgR2xvYmFsX1NhbGVzIikKYGBgCgpgYGB7cn0KZGF0YXNldCRZZWFyICU+JSB0YWJsZSgpICU+JSBiYXJwbG90KCBtYWluID0gIkJhcnBsb3QgZm9yIHllYXIiKQpgYGAKCmBgYHtyfQpwYWlycyh+TkFfU2FsZXMgKyBFVV9TYWxlcyArIEpQX1NhbGVzICsgT3RoZXJfU2FsZXMgKyBHbG9iYWxfU2FsZXMsIGRhdGEgPSBkYXRhc2V0LAogICAgICBtYWluID0gIlNhbGVzIFNjYXR0ZXJwbG90IikKYGBgICAgIApXZSB1c2VkIFNjYXR0ZXJwbG90IHRvIGRldGVybWluZSB0aGUgdHlwZSBvZiBjb3JyZWxhdGlvbiB3ZSBoYXZlIGJldHdlZW4gdGhlIHNhbGVzOyB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1ham9yaXR5IGhhdmUgcG9zaXRpdmUgY29ycmVsYXRpb24gd2l0aCBlYWNoIG90aGVyLiAKIAogCiAgICAgIAojIFByZSAtIHByb2Nlc3NpbmcKCiMgVmFyYWlibGUgdHJhbnNmb3JtYXRpb24KYGBge3J9CmRhdGFzZXQkUmFuaz1hcy5jaGFyYWN0ZXIoZGF0YXNldCRSYW5rKQpgYGAKV2UgdHJhbnNmb3JtZWQgdGhlIFJhbmsgZnJvbSBudW1yaWMgdG8gY2hhcixiZWNhdXNlIHdlIHdpbGwgdXNlIHRoZW0gYXMgb3JkaW5hbCBkYXRhLgoKIyBOdWxsIGNoZWNraW5nCmBgYHtyfQpzdW0oaXMubmEoZGF0YXNldCRSYW5rKSkKTnVsbFJhbms8LWRhdGFzZXRbZGF0YXNldCRSYW5rPT0iTi9BIixdCk51bGxSYW5rCmBgYApjaGVja2luZyBmb3IgbnVsbHMgaW4gUmFuayAodGhlcmUgaXMgbm8gbnVsbHMpCmBgYHtyfQpzdW0oaXMubmEoZGF0YXNldCROYW1lKSkKTnVsbE5hbWU8LWRhdGFzZXRbZGF0YXNldCROYW1lPT0iTi9BIixdCk51bGxOYW1lCmBgYAoKY2hlY2tpbmcgZm9yIG51bGxzIGluIG5hbWUgKHRoZXJlIGlzIG5vIG51bGxzKQoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JFBsYXRmb3JtKSkKTnVsbFBsYXRmb3JtPC1kYXRhc2V0W2RhdGFzZXQkUGxhdGZvcm09PSJOL0EiLF0KCgpgYGAKY2hlY2tpbmcgZm9yIG51bGxzIGluIFBsYXRmb3JtKHRoZXJlIGlzIG5vIG51bGxzKQoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JFllYXIpKQpOdWxsWWVhcjwtZGF0YXNldFtkYXRhc2V0JFllYXI9PSJOL0EiLF0KTnVsbFllYXIKYGBgCmNoZWNraW5nIGZvciBudWxscyBpbiB5ZWFyCndlIHdvbid0IGRlbGV0ZSB0aGUgbnVsbCBhbmQgd2Ugd2lsbCBsZWF2ZSB0aGVtIGFzIGdsb2JhbCBjb25zdGFudCBiZWNhdXNlIHdlIHdhbnQgdGhlIHNhbGVzIGRhdGEgb3V0IG9mIHRoZW0uCgoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JE90aGVyX1NhbGVzKSkKTnVsbE90aGVyX1NhbGVzPC1kYXRhc2V0W2RhdGFzZXQkT3RoZXJfU2FsZXM9PSJOL0EiLF0KCgpgYGAKVGhlcmUgaXMgbm8gbnVsbCB2YWx1ZXMgaW4gdGhlIG90aGVyX3NhbGVzLgoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JEdlbnJlKSkKTnVsbEdlbnJlPC1kYXRhc2V0W2RhdGFzZXQkR2VucmU9PSJOL0EiLF0KTnVsbEdlbnJlCmBgYApjaGVja2luZyBmb3IgbnVsbHMgaW4gR2VucmUodGhlcmUgaXMgbm8gbnVsbHMpCmBgYHtyfQpzdW0oaXMubmEoZGF0YXNldCRQdWJsaXNoZXIpKQpOdWxsUHVibGlzaGVyPC1kYXRhc2V0W2RhdGFzZXQkUHVibGlzaGVyPT0iTi9BIixdCk51bGxQdWJsaXNoZXIKYGBgCmNoZWNraW5nIGZvciBudWxscyBpbiBQdWJsaXNoZXIuCndlIHdvbid0IGRlbGV0ZSB0aGUgbnVsbCBhbmQgd2Ugd2lsbCBsZWF2ZSB0aGVtIGFzIGdsb2JhbCBjb25zdGFudCBhcyBpdCBpcyBiZWNhdXNlIHdlIHdhbnQgdGhlIHNhbGVzIGRhdGEgb2YgdGhlbS4KCgpgYGB7cn0Kc3VtKGlzLm5hKGRhdGFzZXQkR2xvYmFsX1NhbGVzKSkKTnVsbEdsb2JhbF9TYWxlczwtZGF0YXNldFtkYXRhc2V0JEdsb2JhbF9TYWxlc3M9PSJOL0EiLF0KCgpgYGAKVGhlcmUgaXMgbm8gbnVsbCB2YWx1ZXMgaW4gdGhlIEdsb2JhbF9TYWxlcy4KCiMgRW5jb2RpbmcKYGBge3J9CmRhdGFzZXQkUGxhdGZvcm09ZmFjdG9yKGRhdGFzZXQkUGxhdGZvcm0sbGV2ZWxzPWMoIjI2MDAiLCIzRE8iLCIzRFMiLCJEQyIsIkRTIiwiR0IiLCJHQkEiLCJHQyIsIkdFTiIsIkdHIiwiTjY0IiwiTkVTIiwiTkciLCJQQyIsIlBDRlgiLCJQUyIsIlBTMiIsIlBTMyIsIlBTNCIsIlBTUCIsIlBTViIsIlNBVCIsIlNDRCIsIlNORVMiLCJURzE2IiwiV2lpIiwiV2lpVSIsIldTIiwiWDM2MCIsIlhCIiwiWE9uZSIpLCBsYWJlbHM9YygxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOSwyMCwyMSwyMiwyMywyNCwyNSwyNiwyNywyOCwyOSwzMCwzMSkpCmBgYApTaW5jZSBtb3N0IG1hY2hpbmUgbGVhcm5pbmcgYWxnb3JpdGhtcyB3b3JrIHdpdGggbnVtYmVycyBhbmQgbm90IHdpdGggdGV4dCBvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIHRoaXMgY29sdW1uIHdpbGwgYmUgZW5jb2RlZCB0byBmYWNpbGl0YXRlIG91ciBkYXRhIG1pbmluZyB0YXNrLgoKYGBge3J9CmRhdGFzZXQkR2VucmU9ZmFjdG9yKGRhdGFzZXQkR2VucmUsbGV2ZWxzPWMoIkFjdGlvbiIsIkFkdmVudHVyZSIsIkZpZ2h0aW5nIiwiUGxhdGZvcm0iLCJQdXp6bGUiLCJSYWNpbmciLCJSb2xlLVBsYXlpbmciLCJTaG9vdGVyIiwiU2ltdWxhdGlvbiIsIlNwb3J0cyIsIlN0cmF0ZWd5IiwiTWlzYyIpLGxhYmVscz1jKDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyKSkKYGBgClNpbmNlIG1vc3QgbWFjaGluZSBsZWFybmluZyBhbGdvcml0aG1zIHdvcmsgd2l0aCBudW1iZXJzIGFuZCBub3Qgd2l0aCB0ZXh0IG9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgdGhpcyBjb2x1bW4gd2lsbCBiZSBlbmNvZGVkIHRvIGZhY2lsaXRhdGUgb3VyIGRhdGEgbWluaW5nIHRhc2suCgojIE91dGxpZXJzCm91dGxpZXIgb2YgTkFfU2FsZXMKYGBge3J9Ck91dE5BX1NhbGVzID0gb3V0bGllcihkYXRhc2V0JE5BX1NhbGVzLCBsb2dpY2FsID1UUlVFKQpzdW0oT3V0TkFfU2FsZXMpCkZpbmRfb3V0bGllciA9IHdoaWNoKE91dE5BX1NhbGVzID09VFJVRSwgYXJyLmluZCA9IFRSVUUpCk91dE5BX1NhbGVzCkZpbmRfb3V0bGllcgpgYGAKb3V0bGllciBvZiBFVV9TYWxlcwpgYGB7cn0KT3V0RVVfU2FsZXMgPSBvdXRsaWVyKGRhdGFzZXQkRVVfU2FsZXMsIGxvZ2ljYWwgPVRSVUUpCnN1bShPdXRFVV9TYWxlcykKRmluZF9vdXRsaWVyID0gd2hpY2goT3V0RVVfU2FsZXMgPT1UUlVFLCBhcnIuaW5kID0gVFJVRSkKT3V0RVVfU2FsZXMKRmluZF9vdXRsaWVyCmBgYApvdXRsaWVyIG9mIEpQX1NhbGVzCmBgYHtyfQpPdXRKUF9TYWxlcyA9IG91dGxpZXIoZGF0YXNldCRKUF9TYWxlcywgbG9naWNhbCA9VFJVRSkKc3VtKE91dEpQX1NhbGVzKQpGaW5kX291dGxpZXIgPSB3aGljaChPdXRKUF9TYWxlcyA9PVRSVUUsIGFyci5pbmQgPSBUUlVFKQpPdXRKUF9TYWxlcwpGaW5kX291dGxpZXIKYGBgCgpvdXRsaWVyIG9mIG90aGVyX3NhbGVzIApgYGB7cn0KT3V0T1M9b3V0bGllcihkYXRhc2V0JE90aGVyX1NhbGVzLCBsb2dpY2FsPVRSVUUpICAKc3VtKE91dE9TKSAgCkZpbmRfb3V0bGllcj13aGljaChPdXRPUz09VFJVRSwgYXJyLmluZD1UUlVFKSAgCk91dE9TIApGaW5kX291dGxpZXIgCgpgYGAKCgpvdXRsaWVyIG9mIEdsb2JhbF9zYWxlcyAKCmBgYHtyfQpPdXRHUz1vdXRsaWVyKGRhdGFzZXQkR2xvYmFsX1NhbGVzLCBsb2dpY2FsPVRSVUUpICAKc3VtKE91dEdTKSAgCkZpbmRfb3V0bGllcj13aGljaChPdXRHUz09VFJVRSwgYXJyLmluZD1UUlVFKSAgCk91dEdTIApGaW5kX291dGxpZXIgCgpgYGAKCgoKIyBSZW1vdmUgb3V0bGllcnMgCmBgYHtyfQpkYXRhc2V0PSBkYXRhc2V0Wy1GaW5kX291dGxpZXIsXQpgYGAKCgoKIyBOb3JtYWxpemF0aW9uCkRhdGFzZXQgYmVmb3JlIG5vcm1hbGl6YXRpb246CmBgYHtyfQpkYXRzZXRXaXRob3V0Tm9ybWFsaXphdGlvbjwtZGF0YXNldApgYGAKCgpgYGB7cn0Kbm9ybWFsaXplIDwtIGZ1bmN0aW9uKHgpIHtyZXR1cm4gKCh4IC0gbWluKHgpKSAvIChtYXgoeCkgLSBtaW4oeCkpKX0KZGF0YXNldCROQV9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE5BX1NhbGVzKQpkYXRhc2V0JEVVX1NhbGVzPC1ub3JtYWxpemUoZGF0c2V0V2l0aG91dE5vcm1hbGl6YXRpb24kRVVfU2FsZXMpCmRhdGFzZXQkSlBfU2FsZXM8LW5vcm1hbGl6ZShkYXRzZXRXaXRob3V0Tm9ybWFsaXphdGlvbiRKUF9TYWxlcykKZGF0YXNldCRPdGhlcl9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE90aGVyX1NhbGVzKQpkYXRhc2V0JEdsb2JhbF9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJEdsb2JhbF9TYWxlcykKYGBgCldlIGNob3NlIG1pbi1tYXggbm9ybWFsaXphdGlvbiBpbnN0ZWFkIG9mIHotc2NvcmUgbm9ybWFsaXphdGlvbiBiZWNhdXNlIG1pbi1tYXggdHJhbnNmb3JtIHRoZSBkYXRhIGludG8gYSBzcGVjaWZpYyByYW5nZSwgd2hpY2ggZW5oYW5jZXMgaXRzIHN1aXRhYmlsaXR5IGZvciB2aXN1YWxpemF0aW9uIGFuZCBjb21wYXJpc29uLiBBZGRpdGlvbmFsbHksIGl0IHNpbXBsaWZpZXMgdGhlIHByb2Nlc3Mgb2YgYXNzZXNzaW5nIGF0dHJpYnV0ZSBpbXBvcnRhbmNlIGFuZCB0aGVpciBjb250cmlidXRpb25zIHRvIHRoZSBtb2RlbC4KCgoKCgojIEZlYXV0cmUgc2VsZWN0aW9uCk91ciBjbGFzcyBsYWJlbCAocG9wdWxhcikgcmVmZXJzIHRvIEdsb2JhbF9TYWxlcy4gT3RoZXIgc2FsZXMgcmVnaW9ucyB3aWxsIGJlIGV2YWx1YXRlZCBiYXNlZCBvbiB0aGVpciBpbXBvcnRhbmNlIHRvIChnbG9iYWxfc2FsZXMpIGNvbHVtbi4gYW5kIHRob3NlIHRoYXQgYXJlIGxlc3MgaW1wb3J0YW50IHdpbGwgYmUgZGVsZXRlZCBmcm9tIHRoZSBkYXRhc2V0Lgp1c2Ugcm9jX2N1cnZlIGFyZWEgYXMgc2NvcmUKYGBge3J9CnJvY19pbXAgPC0gZmlsdGVyVmFySW1wKHggPSBkYXRhc2V0Wyw3OjEwXSwgeSA9IGRhdGFzZXQkR2xvYmFsX1NhbGVzKQpgYGAKc29ydCB0aGUgc2NvcmUgaW4gZGVjcmVhc2luZyBvcmRlcgpgYGB7cn0Kcm9jX2ltcCA8LSBkYXRhLmZyYW1lKGNiaW5kKHZhcmlhYmxlID0gcm93bmFtZXMocm9jX2ltcCksIHNjb3JlID0gcm9jX2ltcFssMV0pKQpyb2NfaW1wJHNjb3JlIDwtIGFzLmRvdWJsZShyb2NfaW1wJHNjb3JlKQpyb2NfaW1wW29yZGVyKHJvY19pbXAkc2NvcmUsZGVjcmVhc2luZyA9IFRSVUUpLF0KYGBgCndlIHdpbGwgcmVtb3ZlIHRoZSAoSlBfU2FsZXMpIGJlY2F1c2UgaXQgaXMgb2YgbG93IGltcG9ydGFuY2UgdG8gb3VyIGNsYXNzX2xhYmVsKEdsb2JhbF9TYWxlcykKYGBge3J9CmRhdGFzZXQ8LSBkYXRhc2V0WywtOV0KYGBgCgojIERhdGFzZXQgYWZ0ZXIgcHJlLXByb2Nlc3NpbmcKYGBge3J9CnByaW50KGRhdGFzZXQpCmBgYAoK
=======
LS0tDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KI0lUMzI2IFByb2plY3QNCg0KDQoNCg0KIyBEZXNjcmlwdGlvbiBvZiB0aGUgZGF0YXNldDoNCg0KVGhpcyBkYXRhc2V0LCBvYnRhaW5lZCBmcm9tIHZnY2hhcnR6LmNvbSwgcHJvdmlkZXMgYSB2YWx1YWJsZSByZXNvdXJjZSBmb3IgZXhwbG9yaW5nIHRoZSBkeW5hbWljcyBiZXR3ZWVuIGdhbWluZyBwbGF0Zm9ybXMgYW5kIGdlbnJlcyBpbiB0aGUgdG9wIDEwMCBnbG9iYWwgdmlkZW8gZ2FtZXMuIEl0IGVuYWJsZXMgdXMgdG8gYW5hbHl6ZSB0aGUgcGxhdGZvcm1zIHRoYXQgYXJlIGluZmx1ZW5jaW5nIHdvcmxkd2lkZSBzYWxlcywgaWRlbnRpZnkgdGhlIG1vc3QgcHJvc3Blcm91cyBnZW5yZXMgaW4gdmFyaW91cyBnbG9iYWwgcmVnaW9ucywgYW5kIHRyYWNrIHRoZSBldm9sdmluZyB0cmVuZHMgaW4gYm90aCBwbGF0Zm9ybSBwcmVmZXJlbmNlIGFuZCBnZW5yZSBwb3B1bGFyaXR5IG92ZXIgdGltZS4gDQoNCiMgU291cmNlIGFuZCBsaW5rOg0KU291cmNlOiBLYWdnbGUNCg0KVVJMIGxpbms6IGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZ3JlZ29ydXQvdmlkZW9nYW1lc2FsZXMNCg0KIyBPdXIgZ29hbDoNCg0KT3VyIGdvYWwgIGZyb20gc3R1ZHlpbmcgdGhpcyBkYXRhc2V0IGlzIHRvIHV0aWxpemUgY2xhc3NpZmljYXRpb24gYW5kIGNsdXN0ZXJpbmcgdGVjaG5pcXVlcyBvbiB0aGUgaW5wdXQgZGF0YSB0byBtYWtlIHByZWRpY3Rpb25zIGFib3V0IHRoZSBwb3B1bGFyaXR5IG9mIHVwY29taW5nIGdhbWVzLg0KDQoNCg0KIyBBdHRyaWJ1dGVzIGRlc2NyaXB0aW9uOg0KDQoNCnwgKipBdHRyaWJ1dGVzIG5hbWUqKiB8ICoqRGVzY3JpcHRpb24qKiAgICAgICAgICAgICAgICAgICB8ICoqRGF0YSB0eXBlKiogfCANCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnxSYW5rICAgICAgICAgICAgICAgfCBSYW5raW5nIG9mIHRoZSBnYW1lIGJhc2VkIG9uIGdsb2JhbCBzYWxlcy4gfCBOdW1lcmljICAgICAgIHwNCnwgTmFtZSAgICAgICAgICAgIHwgTmFtZSBvZiB0aGUgZ2FtZS4gfCBOb21pbmFsICAgICAgIHwgDQp8IFBsYXRmb3JtICAgICAgfCBQbGF0Zm9ybSB0aGUgZ2FtZSB3YXMgcmVsZWFzZWQgb24uIHwgTm9taW5hbCAgICAgICB8IA0KfCBZZWFyICAgICAgICAgICAgICAgfCBZZWFyIHRoZSBnYW1lIHdhcyByZWxlYXNlZC4gfCBPcmRpbmFsICAgICAgIHwgDQp8IEdlbnJlICAgICAgICAgICAgfCBHZW5yZSBvZiB0aGUgZ2FtZSB8IE5vbWluYWwgICAgICAgfCANCnwgUHVibGlzaGVyICAgICAgfCBQdWJsaXNoZXIgb2YgdGhlIGdhbWUuIHwgTm9taW5hbCAgICAgICB8IA0KfCBOQV9TYWxlcyAgICAgIHwgU2FsZXMgb2YgdGhlIGdhbWUgaW4gTm9ydGggQW1lcmljYSB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgfCANCnwgRVVfU2FsZXMgICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBFdXJvcGUgfCBOdW1lcmljIChyYXRpby1zY2FsZWQpICAgICAgICB8IA0KfCBKUF9TYWxlcyAgICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBKYXBhbiB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgIHwgDQp8IE90aGVyX1NhbGVzIHwgU2FsZXMgb2YgdGhlIGdhbWUgaW4gb3RoZXIgcmVnaW9ucyB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgIHwgDQp8IEdsb2JhbF9TYWxlcyAgfCBUb3RhbCBzYWxlcyBvZiB0aGUgZ2FtZSB3b3JsZHdpZGUgfCBOdW1lcmljIChyYXRpby1zY2FsZWQpICAgICB8ICAgICANCg0KDQojIENsYXNzIGxhYmVsOg0KDQpQb3B1bGFyJyBpcyBvdXIgY2xhc3MgbGFiZWwsIHdlIHdpbGwgdXNlIEdsb2JhbF9TYWxlcyBhdHRyaWJ1dGUgdG8gcHJlZGljdCB3aGV0aGVyIGEgZ2FtZSB3aWxsIHNlbGwgMTAwMDAwMCBvciBtb3JlIGdsb2JhbGx5LiBPdXIgdGFzayBvZiBkYXRhIG1pbmluZyBpcyByZWdyZXNzaW9uLg0KDQoNCg0KDQpgYGB7cn0NCmRhdGFzZXQ9cmVhZC5jc3YoInZnc2FsZXMuY3N2IikNCmBgYA0KSW1wb3J0aW5nIG91ciBkYXRhc2V0Lg0KDQoNCmBgYHtyfQ0KbGlicmFyeShvdXRsaWVycykgDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShIbWlzYykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY293cGxvdCkNCmxpYnJhcnkobWxiZW5jaCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGZhdXgpDQpsaWJyYXJ5KERhdGFFeHBsb3JlcikNCmxpYnJhcnkocmFuZG9tRm9yZXN0KQ0Kb3B0aW9ucyhtYXgucHJpbnQ9OTk5OTk5OSkNCmBgYA0KDQpsb2FkaW5nIGxpYnJhcmllcyBuZWVkZWQgZm9yIG91ciBkYXRhIG1pbmluZyB0YXNrcy4NCg0KDQpgYGB7cn0NCm5yb3coZGF0YXNldCkNCm5jb2woZGF0YXNldCkNCmRpbShkYXRhc2V0KQ0KbmFtZXMoZGF0YXNldCkNCmBgYA0KR2VuZXJhbCBpbmZvIGFib3V0IG91ciBkYXRhc2V0IGluY2x1ZGluZyAgbnVtYmVyIG9mIHJvd3MgYW5kIGNvbHVtbnMsIGFuZCBjaGVraW5nIGRpbWVuc2lvbmFsaXR5IGFuZCBjb3VsdW1ucyBuYW1lcy4NCg0KYGBge3J9DQpzdHIoZGF0YXNldCkNCmBgYA0KRGF0YXNldCBzdHJ1Y3R1cmUgaW5jbHVkaW5nIG51bWJlciBvZiBjb3VsdW1zIGFuZCByb3dzLCBhdHRyaWJ1dGUgdHlwZXMuIA0KDQpgYGB7cn0NCmhlYWQoZGF0YXNldCwgMTApDQpgYGANCnNhbXBsZSBvZiByYXcgZGF0YXNldChmaXJzdCAxMCByb3dzKS4NCg0KYGBge3J9DQp0YWlsKGRhdGFzZXQsIDEwKQ0KYGBgDQpzYW1wbGUgb2YgcmF3IGRhdGFzZXQobGFzdCAxMCByb3dzKS4NCg0KYGBge3J9DQpzdW1tYXJ5KGRhdGFzZXQpDQpgYGANCnN1bW1hcnkgb2Ygb3VyIGRhdGFzZXQuDQoNCmBgYHtyfQ0KdmFyKGRhdGFzZXQkTkFfU2FsZXMpDQp2YXIoZGF0YXNldCRFVV9TYWxlcykNCnZhcihkYXRhc2V0JEpQX1NhbGVzKQ0KdmFyKGRhdGFzZXQkT3RoZXJfU2FsZXMpDQp2YXIoZGF0YXNldCRHbG9iYWxfU2FsZXMpDQpgYGANCnZhcmlhbmNlIG9mIG51bWVyaWMgZGF0YQ0KDQojIEdyYXBoczoNCg0KYGBge3J9DQpkYXRhc2V0MiA8LSBkYXRhc2V0ICU+JSBzYW1wbGVfbig1MCkNCnRhYiA8LSBkYXRhc2V0MiRQbGF0Zm9ybSAlPiUgdGFibGUoKQ0KcHJlY2VudGFnZXMgPC0gdGFiICU+JSBwcm9wLnRhYmxlKCkgJT4lIHJvdW5kKDMpICogMTAwIA0KdHh0IDwtIHBhc3RlMChuYW1lcyh0YWIpLCAnXG4nLCBwcmVjZW50YWdlcywgJyUnKSANCg0KcGllKHRhYiwgbGFiZWxzPXR4dCAsIG1haW4gPSAiUGllIGNoYXJ0IG9mIFBsYXRmb3JtIikgDQoNCmBgYA0KDQpXZSBub3RpY2UgZnJvbSB0aGUgcGllIGNoYXJ0IG9mIHBsYXRmb3JtIGF0dHJpYnV0ZSB0aGF0IHJlbGVhc2luZyBhIGdhbWUgZm9yIFBTIHVzZXJzIHdpbGwgaW5jcmVhc2UgdGhlIHBvcHVsYXJpdHkgb2YgdGhlIGdhbWUgc2luY2UgaXQgaXMgdGhlIG1vc3QgY29tbW9uIHBsYXRmb3JtIGFtb25nIGdhbWVycy4gDQoNCg0KDQoNCg0KYGBge3J9DQojIGNvbG9yaW5nIGJhcnBsb3QgYW5kIGFkZGluZyB0ZXh0DQp0YWI8LWRhdGFzZXQkR2VucmUgJT4lIHRhYmxlKCkgDQoNCnByZWNlbnRhZ2VzPC10YWIgJT4lIHByb3AudGFibGUoKSAlPiUgcm91bmQoMykqMTAwIA0KDQp0eHQ8LXBhc3RlMChuYW1lcyh0YWIpLCAnXG4nLHByZWNlbnRhZ2VzLCclJykgDQoNCmJiIDwtIGRhdGFzZXQkR2VucmUgJT4lIHRhYmxlKCkgJT4lIGJhcnBsb3QoYXhpc25hbWVzPUYsIG1haW4gPSAiQmFycGxvdCBmb3IgUG9wdWxhciBnZW5yZXMgIix5bGFiPSdjb3VudCcsY29sPWMoJ3BpbmsnLCdibHVlJywnbGlnaHRibHVlJywnZ3JlZW4nLCdsaWdodGdyZWVuJywncmVkJywnb3JhbmdlJywncmVkJywnZ3JleScsJ3llbGxvdycsJ2F6dXJlJywnb2xpdmVkcmFiJykpIA0KDQp0ZXh0KGJiLHRhYi8yLGxhYmVscz10eHQsY2V4PTEuNSkgDQpgYGANCkluIHRlcm1zIG9mIGdlbnJlLCBhY3Rpb24gZ2FtZXMgYXJlIHRoZSBtb3N0IHBvcHVsYXIsIGZvbGxvd2VkIGJ5IHNwb3J0cyBhbmQgbXVzaWMgZ2FtZXMuIEl0IGlzIHNhZmUgdG8gYXNzdW1lIHRoYXQgYSBoaWdoIG51bWJlciBvZiBnZW5yZXMgb2YgdGhpcyBuYXR1cmUgZXhpc3QgZHVlIHRvIHRoZWlyIHBvcHVsYXJpdHkgYW5kIHNhbGVzLg0KDQoNCmBgYHtyfQ0KYm94cGxvdChkYXRhc2V0JE5BX1NhbGVzICwgbWFpbj0iDQpCb3hQbG90IGZvciBOQV9TYWxlcyIpDQpgYGANCg0KYGBge3J9DQpib3hwbG90KGRhdGFzZXQkRVVfU2FsZXMsIG1haW49Ig0KIEJveFBsb3QgZm9yIEVVX1NhbGVzIikNCmBgYA0KDQpgYGB7cn0NCmJveHBsb3QoZGF0YXNldCRKUF9TYWxlcyAsIG1haW49Ig0KIEJveFBsb3QgZm9yIEpQX1NhbGVzIikNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCmJveHBsb3QoZGF0YXNldCRPdGhlcl9TYWxlcyAsIG1haW49Ig0KIEJveFBsb3QgZm9yIE90aGVyX1NhbGVzIikgDQpgYGAgIA0KDQpUaGUgYm94cGxvdCBvZiB0aGUgT3RoZXItc2FsZXMgYXR0cmlidXRlIGluZGljYXRlIHRoYXQgdGhlIHZhbHVlcyBhcmUgY2xvc2UgdG8gZWFjaCBvdGhlciAsYW5kIHRoZXJlIGlzIGEgbG90IG9mIG91dGxpZXJzIHNpbmNlIHRoZSBkYXRhc2V0IHJlcHJlc2VudHMgdGhlIGdsb2JhbCBzYWxlcyBvZiB2aWRlbyBnYW1lcy4gDQoNCg0KDQoNCmBgYHtyfQ0KYm94cGxvdChkYXRhc2V0JEdsb2JhbF9TYWxlcyAsIG1haW49IkJveFBsb3QgZm9yIEdsb2JhbF9TYWxlcyIpDQoNCmBgYCAgDQpUaGUgYm94cGxvdCBvZiB0aGUgR2xvYmFsLXNhbGVzIGF0dHJpYnV0ZSBpbmRpY2F0ZSB0aGF0IHRoZSB2YWx1ZXMgYXJlIGNsb3NlIHRvIGVhY2ggb3RoZXIgLGFuZCB0aGVyZSBpcyBhIGxvdCBvZiBvdXRsaWVycyBzaW5jZSB0aGUgZGF0YXNldCByZXByZXNlbnRzIHRoZSBnbG9iYWwgc2FsZXMgb2YgdmlkZW8gZ2FtZXMuIA0KDQoNCg0KDQpgYGB7cn0NCnFwbG90KGRhdGEgPSBkYXRhc2V0LCB4PUdsb2JhbF9TYWxlcyx5PUdlbnJlLGZpbGw9SSgieWVsbG93Iiksd2lkdGg9MC41ICxnZW9tID0gImJveHBsb3QiICwgbWFpbiA9ICJCb3hQbG90cyBmb3IgZ2VucmUgYW5kIEdsb2JhbF9TYWxlcyIpDQpgYGANCg0KYGBge3J9DQpkYXRhc2V0JFllYXIgJT4lIHRhYmxlKCkgJT4lIGJhcnBsb3QoIG1haW4gPSAiQmFycGxvdCBmb3IgeWVhciIpDQpgYGANCg0KYGBge3J9DQpwYWlycyh+TkFfU2FsZXMgKyBFVV9TYWxlcyArIEpQX1NhbGVzICsgT3RoZXJfU2FsZXMgKyBHbG9iYWxfU2FsZXMsIGRhdGEgPSBkYXRhc2V0LA0KICAgICAgbWFpbiA9ICJTYWxlcyBTY2F0dGVycGxvdCIpDQpgYGAgICAgDQpXZSB1c2VkIFNjYXR0ZXJwbG90IHRvIGRldGVybWluZSB0aGUgdHlwZSBvZiBjb3JyZWxhdGlvbiB3ZSBoYXZlIGJldHdlZW4gdGhlIHNhbGVzOyB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1ham9yaXR5IGhhdmUgcG9zaXRpdmUgY29ycmVsYXRpb24gd2l0aCBlYWNoIG90aGVyLiANCiANCiANCiAgICAgIA0KIyBQcmUgLSBwcm9jZXNzaW5nDQoNCiMgVmFyYWlibGUgdHJhbnNmb3JtYXRpb24NCmBgYHtyfQ0KZGF0YXNldCRSYW5rPWFzLmNoYXJhY3RlcihkYXRhc2V0JFJhbmspDQpgYGANClJhbmsgc2hvdWxkIGJlIGNoYXIgYW5kIG5vdCBudW1lcmljLGJlY2F1c2Ugd2Ugd2lsbCB1c2UgdGhlbSBhcyBvcmRpbmFsIGRhdGEuDQoNCiMgTnVsbCBjaGVja2luZw0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRSYW5rKSkNCk51bGxSYW5rPC1kYXRhc2V0W2RhdGFzZXQkUmFuaz09Ik4vQSIsXQ0KTnVsbFJhbmsNCmBgYA0KY2hlY2tpbmcgZm9yIG51bGxzIGluIFJhbmsgKHRoZXJlIGlzIG5vIG51bGxzKQ0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCROYW1lKSkNCk51bGxOYW1lPC1kYXRhc2V0W2RhdGFzZXQkTmFtZT09Ik4vQSIsXQ0KTnVsbE5hbWUNCmBgYA0KDQpjaGVja2luZyBmb3IgbnVsbHMgaW4gbmFtZSAodGhlcmUgaXMgbm8gbnVsbHMpDQoNCmBgYHtyfQ0Kc3VtKGlzLm5hKGRhdGFzZXQkUGxhdGZvcm0pKQ0KTnVsbFBsYXRmb3JtPC1kYXRhc2V0W2RhdGFzZXQkUGxhdGZvcm09PSJOL0EiLF0NCg0KDQpgYGANCmNoZWNraW5nIGZvciBudWxscyBpbiBQbGF0Zm9ybSh0aGVyZSBpcyBubyBudWxscykNCg0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRZZWFyKSkNCk51bGxZZWFyPC1kYXRhc2V0W2RhdGFzZXQkWWVhcj09Ik4vQSIsXQ0KTnVsbFllYXINCmBgYA0KY2hlY2tpbmcgZm9yIG51bGxzIGluIHllYXINCndlIHdvbid0IGRlbGV0ZSB0aGUgbnVsbCBhbmQgd2Ugd2lsbCBsZWF2ZSB0aGVtIGFzIGdsb2JhbCBjb25zdGFudCBhcyBpdCBpcyBiZWNhdXNlIHdlIHdhbnQgdGhlIHNhbGVzIGRhdGEgb2YgdGhlbS4NCg0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRHZW5yZSkpDQpOdWxsR2VucmU8LWRhdGFzZXRbZGF0YXNldCRHZW5yZT09Ik4vQSIsXQ0KTnVsbEdlbnJlDQpgYGANCmNoZWNraW5nIGZvciBudWxscyBpbiBHZW5yZSh0aGVyZSBpcyBubyBudWxscykNCg0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRQdWJsaXNoZXIpKQ0KTnVsbFB1Ymxpc2hlcjwtZGF0YXNldFtkYXRhc2V0JFB1Ymxpc2hlcj09Ik4vQSIsXQ0KTnVsbFB1Ymxpc2hlcg0KYGBgDQpjaGVja2luZyBmb3IgbnVsbHMgaW4gUHVibGlzaGVyLg0Kd2Ugd29uJ3QgZGVsZXRlIHRoZSBudWxsIGFuZCB3ZSB3aWxsIGxlYXZlIHRoZW0gYXMgZ2xvYmFsIGNvbnN0YW50IGFzIGl0IGlzIGJlY2F1c2Ugd2Ugd2FudCB0aGUgc2FsZXMgZGF0YSBvZiB0aGVtLg0KDQpgYGB7cn0NCnN1bShpcy5uYShkYXRhc2V0JE90aGVyX1NhbGVzKSkNCk51bGxPdGhlcl9TYWxlczwtZGF0YXNldFtkYXRhc2V0JE90aGVyX1NhbGVzPT0iTi9BIixdDQoNCg0KYGBgDQpUaGVyZSBpcyBubyBudWxsIHZhbHVlcyBpbiB0aGUgb3RoZXJfc2FsZXMuDQoNCmBgYHtyfQ0Kc3VtKGlzLm5hKGRhdGFzZXQkR2xvYmFsX1NhbGVzKSkNCk51bGxHbG9iYWxfU2FsZXM8LWRhdGFzZXRbZGF0YXNldCRHbG9iYWxfU2FsZXNzPT0iTi9BIixdDQoNCg0KYGBgDQpUaGVyZSBpcyBubyBudWxsIHZhbHVlcyBpbiB0aGUgR2xvYmFsX1NhbGVzLg0KDQojIEVuY29kaW5nDQpgYGB7cn0NCmRhdGFzZXQkUGxhdGZvcm09ZmFjdG9yKGRhdGFzZXQkUGxhdGZvcm0sbGV2ZWxzPWMoIjI2MDAiLCIzRE8iLCIzRFMiLCJEQyIsIkRTIiwiR0IiLCJHQkEiLCJHQyIsIkdFTiIsIkdHIiwiTjY0IiwiTkVTIiwiTkciLCJQQyIsIlBDRlgiLCJQUyIsIlBTMiIsIlBTMyIsIlBTNCIsIlBTUCIsIlBTViIsIlNBVCIsIlNDRCIsIlNORVMiLCJURzE2IiwiV2lpIiwiV2lpVSIsIldTIiwiWDM2MCIsIlhCIiwiWE9uZSIpLCBsYWJlbHM9YygxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOSwyMCwyMSwyMiwyMywyNCwyNSwyNiwyNywyOCwyOSwzMCwzMSkpDQpgYGANClNpbmNlIG1vc3QgbWFjaGluZSBsZWFybmluZyBhbGdvcml0aG1zIHdvcmsgd2l0aCBudW1iZXJzIGFuZCBub3Qgd2l0aCB0ZXh0IG9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgdGhpcyBjb2x1bW4gd2lsbCBiZSBlbmNvZGVkLg0KDQpgYGB7cn0NCmRhdGFzZXQkR2VucmU9ZmFjdG9yKGRhdGFzZXQkR2VucmUsbGV2ZWxzPWMoIkFjdGlvbiIsIkFkdmVudHVyZSIsIkZpZ2h0aW5nIiwiUGxhdGZvcm0iLCJQdXp6bGUiLCJSYWNpbmciLCJSb2xlLVBsYXlpbmciLCJTaG9vdGVyIiwiU2ltdWxhdGlvbiIsIlNwb3J0cyIsIlN0cmF0ZWd5IiwiTWlzYyIpLGxhYmVscz1jKDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyKSkNCmBgYA0KU2luY2UgbW9zdCBtYWNoaW5lIGxlYXJuaW5nIGFsZ29yaXRobXMgd29yayB3aXRoIG51bWJlcnMgYW5kIG5vdCB3aXRoIHRleHQgb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB0aGlzIGNvbHVtbiB3aWxsIGJlIGVuY29kZWQuDQoNCg0KIyBPdXRsaWVycw0Kb3V0bGllciBvZiBOQV9TYWxlcw0KYGBge3J9DQpPdXROQV9TYWxlcyA9IG91dGxpZXIoZGF0YXNldCROQV9TYWxlcywgbG9naWNhbCA9VFJVRSkNCnN1bShPdXROQV9TYWxlcykNCkZpbmRfb3V0bGllciA9IHdoaWNoKE91dE5BX1NhbGVzID09VFJVRSwgYXJyLmluZCA9IFRSVUUpDQpPdXROQV9TYWxlcw0KRmluZF9vdXRsaWVyDQpgYGANCm91dGxpZXIgb2YgRVVfU2FsZXMNCmBgYHtyfQ0KT3V0RVVfU2FsZXMgPSBvdXRsaWVyKGRhdGFzZXQkRVVfU2FsZXMsIGxvZ2ljYWwgPVRSVUUpDQpzdW0oT3V0RVVfU2FsZXMpDQpGaW5kX291dGxpZXIgPSB3aGljaChPdXRFVV9TYWxlcyA9PVRSVUUsIGFyci5pbmQgPSBUUlVFKQ0KT3V0RVVfU2FsZXMNCkZpbmRfb3V0bGllcg0KYGBgDQpvdXRsaWVyIG9mIEpQX1NhbGVzDQpgYGB7cn0NCk91dEpQX1NhbGVzID0gb3V0bGllcihkYXRhc2V0JEpQX1NhbGVzLCBsb2dpY2FsID1UUlVFKQ0Kc3VtKE91dEpQX1NhbGVzKQ0KRmluZF9vdXRsaWVyID0gd2hpY2goT3V0SlBfU2FsZXMgPT1UUlVFLCBhcnIuaW5kID0gVFJVRSkNCk91dEpQX1NhbGVzDQpGaW5kX291dGxpZXINCmBgYA0KDQpvdXRsaWVyIG9mIG90aGVyX3NhbGVzIA0KYGBge3J9DQpPdXRPUz1vdXRsaWVyKGRhdGFzZXQkT3RoZXJfU2FsZXMsIGxvZ2ljYWw9VFJVRSkgIA0Kc3VtKE91dE9TKSAgDQpGaW5kX291dGxpZXI9d2hpY2goT3V0T1M9PVRSVUUsIGFyci5pbmQ9VFJVRSkgIA0KT3V0T1MgDQpGaW5kX291dGxpZXIgDQoNCmBgYA0KDQoNCm91dGxpZXIgb2YgR2xvYmFsX3NhbGVzIA0KDQpgYGB7cn0NCk91dEdTPW91dGxpZXIoZGF0YXNldCRHbG9iYWxfU2FsZXMsIGxvZ2ljYWw9VFJVRSkgIA0Kc3VtKE91dEdTKSAgDQpGaW5kX291dGxpZXI9d2hpY2goT3V0R1M9PVRSVUUsIGFyci5pbmQ9VFJVRSkgIA0KT3V0R1MgDQpGaW5kX291dGxpZXIgDQoNCmBgYA0KDQoNCg0KIyBSZW1vdmUgb3V0bGllcnMgDQpgYGB7cn0NCmRhdGFzZXQ9IGRhdGFzZXRbLUZpbmRfb3V0bGllcixdDQpgYGANCg0KDQoNCiMgTm9ybWFsaXphdGlvbg0KDQpgYGB7cn0NCmRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uPC1kYXRhc2V0DQpgYGANCmRhdGFzZXQgYmVmb3JlIG5vcm1hbGl6YXRpb24NCg0KYGBge3J9DQpub3JtYWxpemUgPC0gZnVuY3Rpb24oeCkge3JldHVybiAoKHggLSBtaW4oeCkpIC8gKG1heCh4KSAtIG1pbih4KSkpfQ0KZGF0YXNldCROQV9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE5BX1NhbGVzKQ0KZGF0YXNldCRFVV9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJEVVX1NhbGVzKQ0KZGF0YXNldCRKUF9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJEpQX1NhbGVzKQ0KZGF0YXNldCRPdGhlcl9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE90aGVyX1NhbGVzKQ0KZGF0YXNldCRHbG9iYWxfU2FsZXM8LW5vcm1hbGl6ZShkYXRzZXRXaXRob3V0Tm9ybWFsaXphdGlvbiRHbG9iYWxfU2FsZXMpDQpgYGANCm1pbi1tYXggbm9ybWFsaXphdGlvbg0Kd2Ugd2lsbCB1c2UgdGhlIG1pbi1tYXggbm9ybWFsaXphdGlvbjsgaXQncyBiZXR0ZXIgZm9yIHZpc3VhbGl6YXRpb24uDQoNCg0KIyBGZWF1dHJlIHNlbGVjdGlvbg0KT3VyIGNsYXNzIGxhYmVsIChwb3B1bGFyKSByZWZlcnMgdG8gR2xvYmFsX1NhbGVzLiBPdGhlciBzYWxlcyByZWdpb25zIHdpbGwgYmUgZXZhbHVhdGVkIGJhc2VkIG9uIHRoZWlyIGltcG9ydGFuY2UgdG8gKGdsb2JhbF9zYWxlcykgY29sdW1uLiBhbmQgdGhvc2UgdGhhdCBhcmUgbGVzcyBpbXBvcnRhbnQgd2lsbCBiZSBkZWxldGVkIGZyb20gdGhlIGRhdGFzZXQuDQp1c2Ugcm9jX2N1cnZlIGFyZWEgYXMgc2NvcmUNCmBgYHtyfQ0Kcm9jX2ltcCA8LSBmaWx0ZXJWYXJJbXAoeCA9IGRhdGFzZXRbLDc6MTBdLCB5ID0gZGF0YXNldCRHbG9iYWxfU2FsZXMpDQpgYGANCnNvcnQgdGhlIHNjb3JlIGluIGRlY3JlYXNpbmcgb3JkZXINCmBgYHtyfQ0Kcm9jX2ltcCA8LSBkYXRhLmZyYW1lKGNiaW5kKHZhcmlhYmxlID0gcm93bmFtZXMocm9jX2ltcCksIHNjb3JlID0gcm9jX2ltcFssMV0pKQ0Kcm9jX2ltcCRzY29yZSA8LSBhcy5kb3VibGUocm9jX2ltcCRzY29yZSkNCnJvY19pbXBbb3JkZXIocm9jX2ltcCRzY29yZSxkZWNyZWFzaW5nID0gVFJVRSksXQ0KYGBgDQp3ZSB3aWxsIHJtb3ZlIHRoZSAoSlBfU2FsZXMpIGJlY2F1c2UgaXQgaXMgb2YgbG93IGltcG9ydGFuY2UgdG8gb3VyIGNsYXNzX2xhYmVsKEdsb2JhbF9TYWxlcykNCmBgYHtyfQ0KZGF0YXNldDwtIGRhdGFzZXRbLC05XQ0KYGBgDQoNCiMgRGF0YXNldCBhZnRlciBwcmUtcHJvY2Vzc2luZw0KYGBge3J9DQpwcmludChkYXRhc2V0KQ0KYGBgDQoNCg==
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f